/***************************************************************************
 * CR_Slinks -- Copyright Bit Armory Labs 2007
 *
 * FILE:     SlinksPlugIn.cs, 70 code lines, [1.66 KB]
 * DATE:     8/25/2007 1:40 PM
 * MODIFIED: 9/5/2007 4:25 AM
 * PATH:     C:\Programming\Projects\Slinks\CR_Slinks
 *
 * NAMESPACE: CR_PageLinks
 * CLASS:     PageLinksPlugIn
 *
 * AUTHOR:   Brian Chavez (Cowboy), bchavez@bitarmory.com
 *
 *                        Licence
 *
 * This library, code generator, and source code
 * is licensed under the terms and conditions defined in the GNU Public
 * License. You are free to use it for non-commercial purposes.
 * If you are going to use any part of it in a commercial 
 * application, contact me and we can work something out.
 * You may use the code generated output of Slink and Slink
 * as a development tool in both commercial and 
 * non-commercial applications.
 *
 * THE SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS", WITHOUT WARRANTY
 * OF ANY KIND, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE AUTHOR BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF THIS
 * SOFTWARE.
 *
 ***************************************************************************/

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using DevExpress.CodeRush.Core;
using DevExpress.CodeRush.Diagnostics.General;
using DevExpress.CodeRush.PlugInCore;
using DevExpress.CodeRush.StructuralParser;
using System.Diagnostics;
using System.Collections.Generic;
using System.Collections;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using Slink.Core;
using Slink.Generator;
using System.Reflection;
using DevExpress.CodeRush.Common;
using CodeSmithParser;
using TaHoGen.Targets;
using DevExpress.CodeRush.Win32;


namespace CR_Slink
{   
    public partial class SlinkPlugIn : StandardPlugIn
    {

        // DXCore-generated code...
        #region InitializePlugIn
        public override void InitializePlugIn()
        {
            base.InitializePlugIn();
            
            //
            // TODO: Add your initialization code here.
            //

            AppDomain.CurrentDomain.AssemblyResolve+=new ResolveEventHandler(CurrentDomain_AssemblyResolve);
        }

        private Assembly CurrentDomain_AssemblyResolve( object sender, ResolveEventArgs args )
        {
            if( args.Name.ToLower().Contains("Slink.Core".ToLower()) )
            {
                //we the assembly in the directory we're executing from. load it
                //and return it.
                return typeof ( SlinkConfigSection ).Assembly;
            }
            else if( args.Name.ToLower().Contains("TaHoGen.Core".ToLower()) )
            {
                return typeof( TaHoGen.Targets.FileTarget ).Assembly;
            }
            else if( args.Name.ToLower().Contains( "Interop.CodeSmithParser".ToLower() ) )
            {
                return typeof ( CDirectiveParserClass ).Assembly;
            }
            else
            {
                return null;
            }
        }
        #endregion
        #region FinalizePlugIn
        public override void FinalizePlugIn()
        {
            //
            // TODO: Add your finalization code here.
            //

            base.FinalizePlugIn();
        }
        #endregion

        private void SlinkPlugin_BuildBegin( EnvDTE.vsBuildScope scope, EnvDTE.vsBuildAction action )
        {
            this.UpdateSlinkProjects();
        }

        private Dictionary<EnvDTE.Project, SlinkManagedWebProject> webProjects = new Dictionary<EnvDTE.Project, SlinkManagedWebProject>();
        private Dictionary<string, FileSystemWatcher> fileSystemWatchers = new Dictionary<string, FileSystemWatcher>();

        private void PageLinksPlugIn_SolutionOpened()
        {
            EnvDTE.Projects solutionProjects = CodeRush.Solution.Active.Projects;
            foreach(EnvDTE.Project project in solutionProjects )
            {
                this.LoadProject( project );
            }

            this.UpdateSlinkProjects();
        }

        /// <summary>
        /// Add slink project
        /// </summary>
        /// <param name="project">Project</param>
        private void LoadProject( EnvDTE.Project project )
        {
            if( project.Kind == ProjectKind.WebProject )
            {
                if ( Slink.Core.SlinkConfigFile.Exists( project.UniqueName ) )
                {
                    //we have a web proejct here.
                    this.webProjects.Add( project, new SlinkManagedWebProject( project.UniqueName ) );
                    FileSystemWatcher projectWatcher = new FileSystemWatcher( project.UniqueName );
                    this.RegisterFileSystemWatcher( projectWatcher );
                    this.fileSystemWatchers.Add( project.UniqueName, projectWatcher );
                }
            }
            else if( project.Kind == ProjectKind.WebAppProject )
            {
                string folderPath = Path.GetDirectoryName( project.FileName );
                if( Slink.Core.SlinkConfigFile.Exists( folderPath ) )
                {
                    //we also have a web app project.
                    this.webProjects.Add( project, new SlinkManagedWebProject( folderPath ) );
                    FileSystemWatcher projectWatcher = new FileSystemWatcher( folderPath );
                    this.RegisterFileSystemWatcher( projectWatcher );
                    this.fileSystemWatchers.Add( folderPath, projectWatcher );
                }
            }
        }

        private void RegisterFileSystemWatcher(FileSystemWatcher fsWatcher)
        {
            fsWatcher.IncludeSubdirectories = true;
            fsWatcher.Created += new FileSystemEventHandler( fsWatcher_Created );
            fsWatcher.Deleted += new FileSystemEventHandler( fsWatcher_Deleted );
            fsWatcher.Renamed += new RenamedEventHandler( fsWatcher_Renamed );
            fsWatcher.EnableRaisingEvents = true;
        }
        
        private void UnregisterFileSystemWatcher( FileSystemWatcher fsWatcher )
        {
            fsWatcher.EnableRaisingEvents = false;
            fsWatcher.Created -= new FileSystemEventHandler( this.fsWatcher_Created );
            fsWatcher.Deleted -= new FileSystemEventHandler( this.fsWatcher_Deleted );
            fsWatcher.Renamed -= new RenamedEventHandler( this.fsWatcher_Renamed );
        }

        
        void fsWatcher_Renamed( object sender, RenamedEventArgs e )
        {
            if( SlinkPlugInSettings.UseFileSystemWatchers )
            {
                this.WriteLineToBuildWindow( "File Renamed: " + e.OldFullPath );
                this.UpdateSlinkProjects();
            }
        }

        void fsWatcher_Deleted( object sender, FileSystemEventArgs e )
        {
            if( SlinkPlugInSettings.UseFileSystemWatchers )
            {
                this.WriteLineToBuildWindow( "File Deleted: " + e.FullPath );
                this.UpdateSlinkProjects();
            }
        }

        void fsWatcher_Created( object sender, FileSystemEventArgs e )
        {
            if( SlinkPlugInSettings.UseFileSystemWatchers )
            {
                this.WriteLineToBuildWindow( "File Created: " + e.FullPath );
                this.UpdateSlinkProjects();
            }
        }


        private void UnloadAllProjects()
        {
            foreach( FileSystemWatcher fsWatcher in this.fileSystemWatchers.Values )
            {
                this.UnregisterFileSystemWatcher( fsWatcher );
            }
        }

        private void UpdateSlinkProjects()
        {
            foreach( SlinkManagedWebProject slinkProject in this.webProjects.Values )
            {
                slinkProject.ConfigFile.RefreshConfig();
                
                if ( slinkProject.ConfigFile.EngineEnabled )
                {
                    this.WriteLineToBuildWindow( "Building typesafe links in " + slinkProject.VsWebProjectFullFilePathOnDisk );
                    slinkProject.GenerateTypesafetyFile();
                    this.WriteLineToBuildWindow( "Done building typesafe links." );
                }
            }
        }


        private void SlinksPlugIn_StartupComplete()
        {
            //Startup Complete occurs when the IDE DxCore load is complete
            //scan for all web projects.
            
        }

        private void SlinkPlugIn_ProjectAdded( EnvDTE.Project project )
        {
            this.LoadProject( project );
        }

        private void SlinkPlugIn_BeginShutdown()
        {
            this.UnloadAllProjects();
        }
        
        

        private void SlinkPlugIn_ProjectRemoved( EnvDTE.Project project )
        {
            if( this.webProjects.ContainsKey( project ) )
            {
                this.webProjects.Remove( project );
            }
            if( this.fileSystemWatchers.ContainsKey( project.UniqueName ) )
            {
                this.UnregisterFileSystemWatcher( this.fileSystemWatchers[project.UniqueName] );
            }
        }
        
        private void SlinkPlugIn_ProjectRenamed( EnvDTE.Project project, string oldName )
        {
            
        }

        /// <summary>
        /// Write to build window
        /// </summary>
        /// <param name="text">Text</param>
        private void WriteToBuildWindow( string text )
        {
            EnvDTE.Window window = CodeRush.Windows.GetWindow( EnvDTE.Constants.vsWindowKindOutput );
            EnvDTE.OutputWindow ow = window.Object as EnvDTE.OutputWindow;

            foreach( EnvDTE.OutputWindowPane owp in ow.OutputWindowPanes )
            {
                if( owp.Name.ToLower().Equals( "build" ) )
                {
                    owp.OutputString( "CR_Slink: " +text );
                }
            }
        }
        /// <summary>
        /// Write line to build window
        /// </summary>
        /// <param name="line">Line</param>
        private void WriteLineToBuildWindow( string line )
        {
            this.WriteToBuildWindow( line + "\r\n" );
        }

        private void SlinkPlugIn_BeforeClosingSolution()
        {
            this.UnloadAllProjects();
        }
    }

    /// <summary>
    /// Project kind
    /// </summary>
    public static class ProjectKind
    {
        public const string WebProject = "{E24C65DC-7377-472b-9ABA-BC803B73C61A}";
        public const string WebAppProject = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}";
    }
    /// <summary>
    /// VSConstants
    /// </summary>
    public static class VSConstants
    {
        public const string BuildOutput = "{1BD8A850-02D1-11D1-BEE7-00A0C913D1F8}";
    }
}